package tk.mybatis.springboot.service.impl;

import org.assertj.core.util.DateUtil;
import org.springframework.stereotype.Service;
import org.springframework.test.annotation.Rollback;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.util.StringUtil;
import tk.mybatis.springboot.mapper.UserMapper;
import tk.mybatis.springboot.model.*;
import tk.mybatis.springboot.service.UserService;
import tk.mybatis.springboot.util.WxUtils;

import javax.annotation.Resource;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.rmi.ServerRuntimeException;
import java.security.SecureRandom;
import java.security.spec.KeySpec;
import java.util.*;

@Service
public class UserServiceImpl implements UserService {
    @Resource
    private CourseServiceImpl courseServiceImpl;

    @Resource
    private UserMapper userMapper;

    private static final int GCM_IV_LENGTH = 12;
    private static final int GCM_TAG_LENGTH = 16;
    private static final int ITERATIONS = 65536;
    private static final int KEY_LENGTH = 256;
    private static final String ALGORITHM = "AES/GCM/NoPadding";
    private static final String KEY_DERIVATION = "PBKDF2WithHmacSHA256";

    // 从密码和盐派生密钥
    public static SecretKey deriveKey(String password, byte[] salt) throws Exception {
        KeySpec spec = new PBEKeySpec(password.toCharArray(), salt, ITERATIONS, KEY_LENGTH);
        SecretKey tmp = SecretKeyFactory.getInstance(KEY_DERIVATION).generateSecret(spec);
        return new SecretKeySpec(tmp.getEncoded(), "AES");
    }

    @Override
    public Students login(String code) {
        String openId = WxUtils.getOpenid(code);
        return userMapper.getByOpenId(openId);
    }

    @Override
    public Students getLoginUser(Students students) {
        return userMapper.getById(students.getId());
    }

    @Override
    public List<StudentsVO> getStudents(StudentsForm students,Boolean getOver) {
        List<StudentsVO> result = new ArrayList<StudentsVO>();
        List<Students> studentsList = userMapper.getStudents(students);
        for (Students student : studentsList) {
            StudentsVO vo = new StudentsVO();
            vo.setStudents(student);
            if(getOver){
                vo.setStudentCourses(userMapper.getClassAndGroup(student.getId()));
            }else {
                vo.setStudentCourses(userMapper.getClassAndGroup2(student.getId()));
            }

            result.add(vo);
        }
        List<StudentsVO> filteredResult = new ArrayList<>();
        if (students.getCurrentSessionNumber().isEmpty() && students.getClassId().isEmpty() && students.getLargeGroupId().isEmpty() && students.getSmallGroupId().isEmpty()) {
            filteredResult = result;
        } else {
            //营期，班级大小组筛选
            for (StudentsVO vo : result) {
                boolean hasMatch = false;
                for (StudentCourse course : vo.getStudentCourses()) {
                    boolean matchSession = students.getCurrentSessionNumber().isEmpty() || students.getCurrentSessionNumber().equals(course.getCurrentSessionNumber());
                    boolean matchClass = students.getClassId().isEmpty() || students.getClassId().equals(course.getClassId());
                    boolean matchLargeGroup = students.getLargeGroupId().isEmpty() || students.getLargeGroupId().equals(course.getLargeGroupId());
                    boolean matchSmallGroup = students.getSmallGroupId().isEmpty() || students.getSmallGroupId().equals(course.getSmallGroupId());
                    if (matchSession && matchClass && matchLargeGroup && matchSmallGroup) {
                        hasMatch = true;
                        break;
                    }
                }
                if (hasMatch) {
                    filteredResult.add(vo);
                }
            }
        }
        return filteredResult;
    }

    @Override
    public Students register(Students students) throws Exception {
        students.setId(UUID.randomUUID().toString());
        String openId = WxUtils.getOpenid(students.getOpenId());
        students.setOpenId(openId);
        students.setCreateTime(DateUtil.formatAsDatetime(DateUtil.now()));
        students.setCreateBy("system");
        students.setUpdateTime(DateUtil.formatAsDatetime(DateUtil.now()));
        students.setUpdateBy("system");
        students.setFace("https://uniapp-mrgx.oss-cn-beijing.aliyuncs.com/uploads/face.jpeg");
        //AES加密密码
        if(StringUtil.isNotEmpty(students.getPassword())){
            students.setPassword(encrypt("mrgxPasswordPlaintext",students.getPassword()));
        }
        userMapper.insertUser(students);
        return userMapper.getByOpenId(openId);
    }
    public static String encrypt(String plaintext, String password) throws Exception {
        // 生成随机盐
        SecureRandom random = SecureRandom.getInstanceStrong();
        byte[] salt = new byte[16];
        random.nextBytes(salt);

        // 生成随机IV
        byte[] iv = new byte[GCM_IV_LENGTH];
        random.nextBytes(iv);

        // 派生密钥
        SecretKey key = deriveKey(password, salt);

        // 初始化加密器
        Cipher cipher = Cipher.getInstance(ALGORITHM);
        GCMParameterSpec paramSpec = new GCMParameterSpec(GCM_TAG_LENGTH * 8, iv);
        cipher.init(Cipher.ENCRYPT_MODE, key, paramSpec);

        // 执行加密
        byte[] ciphertext = cipher.doFinal(plaintext.getBytes(StandardCharsets.UTF_8));

        // 组合盐、IV和密文
        byte[] encrypted = new byte[salt.length + iv.length + ciphertext.length];
        System.arraycopy(salt, 0, encrypted, 0, salt.length);
        System.arraycopy(iv, 0, encrypted, salt.length, iv.length);
        System.arraycopy(ciphertext, 0, encrypted, salt.length + iv.length, ciphertext.length);

        return Base64.getEncoder().encodeToString(encrypted);
    }
    @Override
    public Students setting(Students students) {
        students.setUpdateTime(DateUtil.formatAsDatetime(DateUtil.now()));
        students.setUpdateBy("system");
        userMapper.updateUser(students);
        return userMapper.getById(students.getId());
    }

    @Override
    public List<StudentCourse> getClassAndGroup(String id) {
        return userMapper.getClassAndGroup(id);
    }

    @Override
    public String getWorks(String id) {
        return userMapper.getWorks(id);
    }

    @Override
    public List<HashMap<String, String>> getResource(GetResourceBody body) {
        if (body.getLevel().equals("1")) {
            return userMapper.getResource1(body.getParentId());
        } else if (body.getLevel().equals("2")) {
            return userMapper.getResource2(body.getParentId());
        } else if (body.getLevel().equals("3")) {
            return userMapper.getResource3(body.getParentId());
        } else {
            throw new RuntimeException("参数异常");
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public int setCourse(StudentCourse studentCourse) {
        List<String> ids = Arrays.asList(studentCourse.getStudentId().split(","));
        for (String id : ids) {
            studentCourse.setStudentId(id);
            studentCourse.setCourseId(studentCourse.getClassId());
            userMapper.deleteStudentCourseRecord(studentCourse);
            userMapper.insertStudentCourseRecord(studentCourse);
        }
        return ids.size();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int setAward(AwardRequest awardRequest) {

        for (AwardRecord awardRecord : awardRequest.getAwardRecords()) {
            awardRecord.setAwardName(awardRequest.getAward());
            awardRecord.setStudentName(userMapper.getById(awardRecord.getStudentId()).getName());
            awardRecord.setAwarderId(awardRequest.getId());
            userMapper.deleteAward(awardRecord.getStudentId(), awardRecord.getAwardName(), awardRecord.getSmallGroupId());
            userMapper.addAward(awardRecord);
        }
        return awardRequest.getAwardRecords().size();
    }


    @Override
    public List<AwardRecord> getAward(GetAwardBody getAwardBody) {
        //1获取自己的，2获取别人的
        if (getAwardBody.getType().equals("1")) {
            return userMapper.getAwardBody1(getAwardBody.getId());

        } else  {
            return userMapper.getAwardBody2(getAwardBody.getId());
        }
    }

    @Override
    public List<Certificate> getCertificate(GetAwardBody getAwardBody) {
        return userMapper.getCertificate(getAwardBody.getId());
    }

    @Override
    public void setFace(Students students) {
        userMapper.setFace(students.getFace(), students.getId());
    }

    @Override
    public List<Homework> getWork(Homework homework) {
        return userMapper.getHomework(homework.getSessionNumber(), homework.getClassId());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void setWork(HomeworkParams params) {
        userMapper.deleteWork(params.getSessionNumber(), params.getClassId());
        for (int i = 0; i < params.getAssignments().size(); i++) {
            Homework homework = new Homework();
            homework.setId(UUID.randomUUID().toString());
            homework.setSessionNumber(params.getSessionNumber());
            homework.setClassId(params.getClassId());
            homework.setContent(params.getAssignments().get(i).getContent());
            homework.setDays(params.getAssignments().get(i).getDays());
            homework.setTitle(params.getAssignments().get(i).getTitle());
            homework.setType(params.getAssignments().get(i).getType());
            userMapper.addWork(homework);
        }
    }

    @Override
    public List<Homework> getWorkToday(StudentCourse students) {
        //先看看学生学到哪一天了
        String days = userMapper.getClassDays(students.getStudentId(), students.getClassId());
        return userMapper.getHomeworkByDays(students.getClassId(), students.getCurrentSessionNumber(), days);
    }

    @Override
    public List<Homework> getNoWork(StudentCourse students) {
        String days = userMapper.getClassDays(students.getStudentId(), students.getClassId());
        return userMapper.getNoWork(students.getClassId(), students.getCurrentSessionNumber(), days, students.getStudentId());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void overWork(StudentWork studentWork) {
        //删除原作业痕迹
        userMapper.deleteStudentHomework(studentWork.getStudentId(), studentWork.getWorkId());
        userMapper.addStudentHomework(studentWork.getStudentId(), studentWork.getWorkId());
        //到下一天
        this.upDays(studentWork.getStudentId(), studentWork.getWorkId());
        this.upClass(studentWork.getStudentId(), studentWork.getWorkId());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addHomeWork(HomeworkInfo homework) {
        homework.setId(UUID.randomUUID().toString());
        Students students = userMapper.getById(homework.getStudentId());
        homework.setFace(students.getFace());
        homework.setName(students.getName());
        userMapper.deleteHomework(homework.getStudentId(), homework.getWorkId());
        userMapper.addHomeWork(homework);
        userMapper.deleteStudentHomework(homework.getStudentId(), homework.getWorkId());
        userMapper.addStudentHomework(homework.getStudentId(), homework.getWorkId());
        this.upDays(students.getId(), homework.getWorkId());
        this.upClass(students.getId(), homework.getWorkId());
    }


    private void upDays(String studentId, String workId) {
        //拿到课程id和天数
        Homework homework = userMapper.getClassIdByWork(workId);
        //看看今天的课程有多少还没完成了
        Integer overWorkNum = userMapper.getNotOverWorkNum(homework.getClassId(), homework.getSessionNumber(), homework.getDays(), studentId);
        if (overWorkNum == 0 && !homework.getDays().equals("12")) {
            userMapper.upDaysById(studentId, homework.getClassId());
        }
    }

    private void upClass(String studentId, String workId) {
        //拿到课程id和天数
        Homework homework = userMapper.getClassIdByWork(workId);
        //看看这个班还有多少作业没完成
        Integer overWorkNum = userMapper.getClassNotOverWorkNum(homework.getClassId(), homework.getSessionNumber(), studentId);
        //升班
        if (overWorkNum <= 2) {
            //发结业证书
            if (userMapper.getCertificateNum(studentId,homework.getClassId()) == 0) {
                Certificate certificate = new Certificate();
                certificate.setId(UUID.randomUUID().toString());
                certificate.setClassId(homework.getClassId());
                certificate.setClassName(getClassNameById(homework.getClassId()));
                certificate.setStudentId(studentId);
                certificate.setName(userMapper.getById(studentId).getName());
                userMapper.insertCertificate(certificate);
            }
            if (homework.getClassId().equals("4")) {

            } else {
                StudentCourse studentCourse = new StudentCourse();
                studentCourse.setStudentId(studentId);
                studentCourse.setClassId(String.valueOf(Integer.valueOf(homework.getClassId()) + 1));
                studentCourse.setCurrentSessionNumber(homework.getSessionNumber());
                courseServiceImpl.signUp(studentCourse,true);
            }
        }
    }

    public String getClassNameById(String classId) {
        if(classId.equals("1")){
            return "格物班";
        }
        if(classId.equals("2")){
            return "致知班";
        }
        if(classId.equals("3")){
            return "正心班";
        }
        if(classId.equals("4")){
            return "诚意班";
        }
        return "格物班";
    }

    @Override
    public List<Homework> getWorksBySession(Homework homework) {
        return userMapper.getWorksBySession(homework.getClassId(), homework.getSessionNumber());

    }


    @Override
    public List<HomeworkInfo> getOtherWork(HomeworkInfo homework) {
        List<HomeworkInfo> homeworkInfoList = userMapper.getOtherWork(homework);
        for (HomeworkInfo homeworkInfo : homeworkInfoList) {
            homeworkInfo.setComments(userMapper.selectCommentById(homeworkInfo.getId()));
        }
        return homeworkInfoList;
    }

    @Override
    public void like(HomeworkInfo homework) {
        userMapper.setLikeCount(homework.getId());
    }

    @Override
    public void addComment(Comment comment) {
        Students students = userMapper.getById(comment.getStudentId());
        comment.setFace(students.getFace());
        comment.setName(students.getName());
        userMapper.insertComment(comment);
    }

    @Override
    public CourseSession getVideo(CourseSession session) {
        return userMapper.getVideo(session.getCourseId(), session.getSessionNumber());
    }

    @Override
    public void setVideo(CourseSession session) {
        userMapper.setVideo(session.getVideoUrl(), session.getCourseId(), session.getSessionNumber());
    }

    @Override
    public void setTimes(CourseSession session) {
        userMapper.setTimes(session.getStartWith(), session.getEndWith(), session.getId());

    }


}
